[Previous] [Next]

The Toolbar Control

The majority of Windows applications include one or more toolbars, which offer the end user the convenience of executing the most common commands with a click of the mouse. Toolbars should never replace menus—and for good reason: menus can be operated with the keyboard; toolbars can't—but they surely make a program more usable and give it a modern look and feel.

Visual Basic comes with a Toolbar control that can contain buttons and other controls and that can be interactively customized by the end user. The Visual Basic 6 version adds the flat style made popular by Microsoft Internet Explorer and the support for building drop-down menus.

The Toolbar control exposes the Buttons collection, which in turn contains Button objects. Each Button object can be an actual push button, a separator, or a placeholder for another control placed on the toolbar (typically a TextBox control or a ComboBox control). In addition, a Button object exposes the ButtonsMenus collection, where each ButtonMenu object is an item of a drop-down menu. (If the Button object isn't a drop-down menu, this collection is empty.)

Click to view at full size.

Setting Design-Time Properties

In most cases, you define the appearance of a Toolbar at design time and then simply react to user's clicks on its buttons. You have two ways to work with a Toolbar at design time: by using the Toolbar Wizard or by manually setting properties. The two methods aren't mutually exclusive: In most cases, in fact, you might find it convenient to create a first version of a Toolbar control using the wizard and then refine it in its Properties dialog box.

The Toolbar Wizard

The Toolbar Wizard is a new add-in provided with Visual Basic 6. But you won't find this wizard in the list of installable add-ins in the Add-In Manager dialog box. Instead, you have to install the Application Wizard add-in: After you do this, you'll find the Toolbar Wizard command in the Add-In menu. If you select this command, the wizard adds a new Toolbar control to the current form and lets you customize it. Or you can place a Toolbar control on the form yourself, and the wizard will be automatically activated.

Using the Toolbar Wizard is simple. You have a list of buttons in the leftmost list box (see Figure 10-14) from which you select the buttons you want to add to the Toolbar control. You can move items between the two list boxes and change their order in the toolbar by using the provided push buttons, or you can use drag-and-drop. The wizard also creates the companion ImageList control on the form. When you complete a toolbar, you'll be asked whether you want to save it in an .rwp profile file, which lets you speed up the creation of similar toolbars in future applications.

Click to view at full size.

Figure 10-14. Creating a toolbar using the Toolbar Wizard.

General properties

After you create a toolbar, you can access its Property Pages by right-clicking on it and choosing Properties. The General tab of the Property Pages dialog box includes most of the design-time properties that let you control the fine points of the appearance and behavior of a Toolbar control, as shown in Figures 10-15 and 10-16. For example, you make the following decisions: Whether the end user can customize the toolbar at run time (AllowCustomize property), whether the toolbar will wrap on multiple lines when the form is resized (Wrappable property), whether ToolTips are visible (ShowTips property), and what the default size of buttons (ButtonWidth and ButtonHeight properties) is. If necessary, buttons are automatically enlarged to account for their caption or image, so in most cases you don't need to edit the default values of the latter two properties.

A few new properties let you access the most interesting features introduced in Visual Basic 6. You can create flat toolbars by setting the Style property to the value 1-tbrFlat, and you can use the TextAlignment property to modify the alignment of a button's caption with respect to the button's image (0-tbrTextAlignBottom or 1-tbrTextAlignRight).

A toolbar's button can be in three possible states: normal, disabled, or selected. (The selected state occurs when the mouse passes over the button if Style is 1-tbrFlat.) Instead of having three properties to point to different images of the same ImageList control, the Toolbar control uses a different approach: Each Button object exposes only one Image property—an index or a string key—and the state of the button implicitly affects which ImageList control will be used. You assign these three ImageList controls to the ImageList, DisabledImageList, and HotImageList properties either at design time or at run time. For example, you can mimic the behavior of Internet Explorer 4 by using a set of black-and-white icons for the normal state and a set of colorful icons for the selected state. If you don't assign the latter two properties, the Toolbar automatically creates a suitable image for the disabled or selected state.

Figure 10-15. The General tab of the Property Pages dialog box of a Toolbar control.

Figure 10-16. The Buttons tab of the Property Pages dialog box of a Toolbar control.

Button objects

A Toolbar control without any Button objects is useless. You can add Button objects using the Toolbar Wizard, as I explained previously, or you can do it in the Buttons tab of the Property Pages dialog box, as you can see in Figure 10-16. Each Button has a Caption property (use an empty string if you want to display only the icon), an optional Description that appears during a customization operation, a Tag property, a Key in the Buttons collection (optional, but use it to improve the readability of your code), a ToolTipText that appears if the Toolbar's ShowTips property is True, and an Image index or key to the associated ImageList controls.

Style is the most interesting property of a Button object. This property affects the appearance and behavior of the button and can be assigned one of the following values: 0-tbrDefault (a normal button, which behaves like a push button), 1-tbrCheck (a button that stays down when pressed, much like a CheckBox control), 2-tbrButtonGroup (a button that belongs to a group in which only one item can be in the selected state, similar to an OptionButton control), 3-tbrSeparator (a separator of fixed width), 4-tbrPlaceholder (a separator whose size depends on the Width property; this style is used to make room for another control placed on the toolbar), or 5-tbrDropDown (a button with a down arrow beside it, which displays a drop-down menu when clicked).

When the Style property is set to the value 5-tbrDropDown, you can add one or more ButtonMenu objects to the current Button. (You can create ButtonMenu items regardless of the button's style, but they're visible only when the style is tbrDropDown.) Each ButtonMenu object has a Text property (the caption of the menu line), an optional Key in the ButtonMenus collection, and a Tag property. Unfortunately, you can't associate an image with a ButtonMenu object: Drop-down menus are inherently text-only, which definitely contrasts with the graphical nature of the Toolbar control. See Figure 10-17 for an example of a Toolbar control whose first button has an associated drop-down menu.

Figure 10-17. A toolbar with a drop-down menu.

Run-Time Operations

Once you have added a Toolbar control to a form, you have to trap the user's actions on it. You might also need to programmatically build the control at run time or let the user customize it and save the new layout for subsequent sessions.

Creating Button and ButtonMenu objects

You can create new Button objects at run time using the Add method of the Buttons collection, which has the following syntax:

Add([Index], [Key], [Caption], [Style], [Image]) As Button

Index is the position at which the Button object will be inserted in the collection, Key is its optional string key, Caption is the text visible on the toolbar, Style determines the type of the button being added (0-tbrNormal, 1-tbrCheck, 2tbrButtonGroup, 3-tbrSeparator, 4-tbrPlaceholder, or 5-tbrDropDown), and Image is the index or the key of an image in the three companion ImageList controls.

You might want to set a few additional properties when you're creating a Button object, such as Width (for placeholder buttons) and ToolTipText. Buttons whose style is tbrCheck or tbrButtonGroup can be created in a pressed state by assigning 1-tbrPressed to the Value property. Here's an example of code that adds a few buttons:

' A button that can be in an on or off state
Dim btn As Button
Set btn = Toolbar1.Buttons.Add(, , , tbrCheck, "Lock")
btn.Value = tbrPressed
' A separator
Toolbar1.Buttons.Add, , , tbrSeparator
' Two buttons that are mutually exclusive
Set btn = Toolbar1.Buttons.Add(, , , tbrButtonGroup, "Green")
Set btn = Toolbar1.Buttons.Add(, , , tbrButtonGroup, "Red")
btn.Value = tbrPressed

You can place any control in the toolbar by creating a Button object with the Style property set to tbrPlaceholder and then moving the control to the correct position. For example, let's say that you want to place the cboFontSizes control in the toolbar:

' Create a placeholder of proper width.
Dim btn As Button
Set btn = Toolbar1.Buttons.Add(, , , tbrPlaceholder)
btn.Width = cboFontSizes.Width
' Move the ComboBox control over the placeholder button.
Set cboFontSizes.Container = Toolbar1
cboFontSizes.Move btn.Left, btn.Top

If you create a Button object whose Style property is tbrDropDown, you can add one or more items to its ButtonMenus collection by using the collection's Add method:

Add ([Index], [Key], [Text]) As ButtonMenu

Index is the position in the collection, Key is an optional key, and Text is the caption of the menu item. The piece of code below adds one drop-down Button object with a menu of three items.

Dim btn As Button
Set btn = Toolbar1.Buttons.Add(, , , tbrDropDown, "New")
With btn.ButtonMenus
    .Add , , "File"
    .Add , , "Document"
    .Add , , "Image"
End With

Reacting to a user's actions

When the user clicks on a button, the Toolbar control fires a ButtonClick event, so it's easy to execute a piece of code when this happens:

Private Sub Toolbar1_ButtonClick(ByVal Button As MSComCtlLib.Button)
    Select Case Button.Key
        Case "New"
            Call mnuFileNew_Click
        Case "Save"
            Call mnuFileSave_Click
        ' And so on.
    End Select
End Sub

Visual Basic 6 introduces two new events, both of which are related to drop-down menus. The ButtonDropDown event fires when the user opens a drop-down menu. You can use this event to create or modify the menu on the fly—for example, by setting the Visible or Enabled property of its individual ButtonMenu items or by adding new menu lines:

Private Sub Toolbar1_ButtonDropDown(ByVal Button As MSComctlLib.Button)
    ' Make the "Open | Image" command unavailable if necessary.
    If Button.Caption = "Open" Then
        Button.ButtonMenus("Image").Enabled = ImagesAreEnabled
    End If
End Sub

The ButtonMenuClick event fires when the end user actually selects a command in a drop-down menu:

Private Sub Toolbar1_ButtonMenuClick(ByVal ButtonMenu As 
    MSComctlLib.ButtonMenu)
    Select Case ButtonMenu.Key
        Case "Document"
            Call mnuFileNewDocument
        Case "Image"
            Call mnuFileNewImage
    End Select
End Sub

Customizing the Toolbar control

You can allow for users to customize the Toolbar control if you want. You can choose from two ways to achieve this: You set the AllowCustomization property to True to let users enter customization mode by double-clicking on the toolbar, or you programmatically enter customization mode by executing the Toolbar's Customize method. The latter approach is necessary if you want to provide this capability only to a restricted group of users:

Private Sub Toolbar1_DblClick()
    If UserIsAdministrator Then Toolbar1.Customize
End Sub

Whatever method you choose, you end up displaying the Customize Toolbar dialog box, shown in Figure 10-18.

Click to view at full size.

Figure 10-18. The Customize Toolbar dialog box.

When the user closes this dialog box, the Toolbar control raises a Change event. (Beware: This event occurs even if the user made no changes to the toolbar's layout.) Within this event procedure, you should execute a SaveToolbar method, which has the following syntax:

SaveToolbar Key, Subkey, Value

Key is the name of a Registry key, SubKey is the name of a Registry subkey, and Value is the name of a Registry value; together, these arguments define a location in the system Registry where the layout of the toolbar is stored. For example, you can use them to save different layouts depending on the application's name, the user currently logged in, and the particular toolbar:

Private Sub Toolbar1_Change()
    Toolbar1.SaveToolbar "MyApplication", UserName, "MainFormToolbar"
End Sub

You restore these settings using the RestoreToolbar method, typically in the Form_Load event procedure:

Private Sub Form_Load()
    Toolbar1.RestoreToolbar "MyApplication", UserName, "MainFormToolbar"
End Sub

NOTE
Oddly, the RestoreToolbar method raises a Change event. This behavior is usually harmless because the code in this event procedure proceeds to save the toolbar again in the Registry (adding just a little overhead to the form-loading process). However, if the Toolbar object's Change event procedure contains other, time-consuming statements, they might slow down your code and even cause an unexpected error.

When the Customize Toolbar dialog box is active, users can delete existing buttons, restore buttons that had been previously deleted, or change the order of buttons in the toolbar. If you want to let users add buttons, you must create such buttons at design time, run the application, invoke the Customize Toolbar, and delete these extra buttons. The deleted buttons will be available in the leftmost list box in the Customize Toolbar dialog box in case a user wants to restore them.